﻿using Spider.Framework.UtilityCommon;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Spider.Framework.UtilityCommon.Extensions;
using MyCrawler.Entity;
using MyCrawler.Dals;
using System.Threading;
using MyCrawler.Utilyties;

namespace MyCrawler.Controls
{
    public class ZingForumCtr : ForumsCtr
    {
        /// <summary>
        /// source code: vBulletin 4.1.12
        /// </summary>
        public ZingForumCtr()
        {
            _source = "diendan.zing.vn";
            _domain = "http://diendan.zing.vn/";
            _linkInit = "http://diendan.zing.vn/";
            _pageLimit = -1;
            _blockId = DateTime.Now.ToString("yyyyMMddhhmmss");
        }

        /// <summary>
        /// Contructor thứ 2
        /// </summary>
        /// <param name="source">nguồn</param>
        /// <param name="linkInit">link khởi tạo</param>
        /// <param name="domain">domain gốc - có thể trùng với link khởi tạo</param>
        /// <param name="blockId">mỗi lần khởi tạo sẽ có 1 block id, chứa list các thread</param>
        public ZingForumCtr(string source, string linkInit, string domain, string blockId)
        {
            _source = source;
            _linkInit = linkInit;
            _domain = domain; // dùng cho các trang sub trở đi, vì sẽ nối trang với domain
            _blockId = blockId;

            _pageLimit = -1;
        }

        /// <summary>
        /// Lấy danh sách link của các catagories
        /// </summary>
        /// <param name="link"></param>
        /// <returns></returns>
        public override List<string> GetCatalogByLink()
        {
            try
            {
                string s = GetWebContent(_linkInit, 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip;

                string pattForum = @"<li[\s]+id='forum[\d]+'[\s]+class='forumbit_post[\s]+old[\s]+L2'>.*?<\/div>[\s]+<\/div><\/li>";

                var lsForum = s.GetElements(pattForum, false, PatternType.Regex);

                if (lsForum == null || lsForum.Count == 0)
                {
                    return null;
                }

                List<string> ls = new List<string>();

                for (int i = 0; i < lsForum.Count; i++) // item có dạng: div data-href='tintuc/' data-order='1'
                {
                    // kiểm tra có tồn tại sub forum không
                    bool hasSub = Regex.IsMatch(lsForum[i], @"<div[\s]+class='subforums'>");

                    if (hasSub == true) // có forum con
                    {
                        #region lấy các forum con
                        List<string> lsLink = UtilityCtr.GetListItem(lsForum[i], @"href='forumdisplay.php.*?'");
                        if (lsLink.Count > 1)
                        {
                            for (int j = 1; j < lsLink.Count; j++) // chạy từ 1 vì index 0 là link của Cha nó
                            {
                                string linkCat = _linkInit + lsLink[j].Replace("href='", "").Replace("'", "");

                                // làm sạch link
                                string[] arrLink = linkCat.Split('?');
                                if (arrLink.Length > 0)
                                {
                                    linkCat = arrLink[0];
                                }

                                // đưa link vào danh sách
                                ls.Add(linkCat);

                                #region cố gắng truy cập vào trang này xem có con nữa không!
                                string htmlContent_2 = GetWebContent(linkCat, 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip;

                                string htmlForumSub = UtilityCtr.GetItemFirst(htmlContent_2, @"<div[\s]+id='forumbits'[\s]+class='forumbits'>.*?<div[\s]+id='below_threadlist'.*?>");

                                if (htmlForumSub != "")
                                {
                                    // xóa đi threadlist chứa các topic nếu có
                                    htmlForumSub = Regex.Replace(htmlForumSub, @"<div[\s]+id='threadlist'[\s]+class='threadlist'>[\s\S]+", "");

                                    List<string> lsLink_2 = UtilityCtr.GetListItem(htmlForumSub, @"href='forumdisplay.php.*?'");

                                    for (int k = 0; k < lsLink_2.Count; k++) // chạy từ 1 vì index 0 là link của Cha nó
                                    {
                                        string linkCat_2 = _linkInit + lsLink_2[k].Replace("href='", "").Replace("'", "");

                                        // làm sạch link
                                        string[] arrLink_2 = linkCat_2.Split('?');
                                        if (arrLink_2.Length > 0)
                                        {
                                            linkCat_2 = arrLink_2[0];
                                        }

                                        // đưa link vào danh sách
                                        ls.Add(linkCat_2);
                                    }
                                }
                                #endregion
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        string linkCat = _linkInit + UtilityCtr.GetItemFirst(lsForum[i], @"href='forumdisplay.php.*?'").Replace("href='", "").Replace("'", "");

                        // làm sạch link
                        string[] arrLink = linkCat.Split('?');
                        if (arrLink.Length > 0)
                        {
                            linkCat = arrLink[0];
                        }

                        ls.Add(linkCat); // đưa link vào danh sách
                    }
                }

                return ls;
            }
            catch { }
            return null;
        }

        public override void GetListTopic_InCatagory(string lnkCat)
        {
            try
            {
                TraceLog_Status(_source, _blockId, " + " + lnkCat);

                string s = GetWebContent(lnkCat, 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip;
               
                if (s.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                GetTopicsInPage(s, 1);

                #region lấy các chủ đề từ trang thứ 2 trờ đi - nếu có
                try
                {
                    string pager = s.GetElement(@"Trang[\s]+[\d]+[\s]+trong[\s]+[\d]+<\/a>", false, PatternType.Regex);
                    List<string> lsNumPage = UtilityCtr.GetListItem(pager, @"[\d]+");

                    int totalPage = Convert.ToInt32(lsNumPage[lsNumPage.Count - 1]);
                    _pageLimit = -1; // khởi tạo trang giới hạn
                    for (int j = 2; j <= totalPage; j++) // duyêt từ trang số 2 trở đi
                    {
                        if (_pageLimit != -1 && j > _pageLimit) // đã tìm thấy trang giới hạn, trang này có ngày cập nhật nhỏ hơn ngày giới hạn
                        {
                            break;
                        }

                        s = GetWebContent(lnkCat + "/page" + j, 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip;;

                        // trang 2 trở đi phải loại bỏ cụm sticky vì đã xuất hiện ở trang 1
                        s = Regex.Replace(s, @"<ol[\s]+id='stickies'[\s]+class='stickies'>.*?<\/ol>", "");

                        GetTopicsInPage(s, j); // lấy các chủ đề của trang 1
                    }
                }
                catch { }
                #endregion
            }
            catch { }
        }

        /// <summary>
        /// Lấy các topic trong từng trang (có phân trang)
        /// </summary>
        /// <param name="contentHtml"></param>
        /// <param name="pageIndex"></param>
        private void GetTopicsInPage(string contentHtml, int pageIndex)
        {
            try
            {
                var lsTopic = UtilityCtr.GetListItem(contentHtml, @"<li[\s]+class='threadbit[\s\S]+?'[\s]+id='thread_[\d]+'>.*?<\/dl><\/div><\/li>");

                if (lsTopic == null || lsTopic.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- không tìm thấy Topic, kiểm tra Catagorie này có thay đổi source code!"); // ghi log để test
                    return;
                }

                for (int i = 0; i < lsTopic.Count; i++)
                {
                    string sDDTag = UtilityCtr.GetItemFirst(lsTopic[i], @"<dd>([\d]+-[\d]+-[\d]+|Hôm nay|Hôm qua),.*?<\/span>"); //ex: <dd>14-02-13, <span class='time'>12:51 PM</span>

                    if (sDDTag.IsStringNullOrEmpty())
                    {
                        bool isMoved = Regex.IsMatch(lsTopic[i], @"class='[\D\d]+moved[\s]{0,}'");
                        if (isMoved == false)
                        {
                            TraceLog_Status(_source, _blockId, " --- Ngày 'last reply' không tồn tại, có thể chủ đề đã bị xóa, đã di chuyển, hay website nguồn có sự thay đổi souce code!");
                        }
                        continue;
                    }

                    try
                    {
                        #region làm việc với ngày
                        string day = "";

                        string hour = UtilityCtr.GetItemFirst(sDDTag, @"[\d]+:[\d]+[\s]+(AM|PM)");
                        if (sDDTag.ToLower().Contains("hôm nay"))
                        {
                            day = DateTime.Now.ToString("yyyy-MM-dd") + " " + hour;
                        }
                        else
                        {
                            if (sDDTag.ToLower().Contains("hôm qua"))
                            {
                                day = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd") + " " + hour;
                            }
                            else
                            {
                                string sDay = UtilityCtr.GetItemFirst(sDDTag, @"[\d]+-[\d]+-[\d]+");
                                // chuyển về dạng yyyy-MM-dd
                                string[] arrDay = sDay.Split('-');

                                if (arrDay.Length == 3)
                                {
                                    string y = arrDay[2];
                                    if (!y.Contains("20"))
                                    {
                                        y = "20" + y;
                                    }

                                    day = y + "-" + arrDay[1] + "-" + arrDay[0] + " " + hour;
                                }
                            }
                        }
                        #endregion

                        DateTime dtLastDate = Convert.ToDateTime(day);

                        // kiểm tra ngày này có nhỏ hơn ngày giới hạn lấy hay không?
                        if (dtLastDate >= _dtLimit)// trong thời gian 30 ngày mà không có ai trả lời, không lấy dữ liệu mới về nữa
                        {
                            #region thực hiện lấy data
                            // lấy link
                            string link = _linkInit + UtilityCtr.GetItemFirst(lsTopic[i], @"(href='showthread.php).*?'").Replace("href='", "").Replace("'", "");
                            if (link.IsStringNullOrEmpty() == true)
                            {
                                TraceLog_Status(_source, _blockId, " --- Link của topic rỗng, có thể website nguồn có sự thay đổi souce code!");
                                continue; // chạy tới topic kế mà không quan tâm đoạn dưới
                            }

                            // làm sạch link
                            string[] arrLink = link.Split('?');
                            if (arrLink.Length > 0)
                            {
                                link = arrLink[0];
                            }

                            // lấy id
                            int id;
                            try
                            {
                                id = Convert.ToInt32(UtilityCtr.GetItemFirst(link, @"\/[\d]+-").Replace("/", "").Replace("-", ""));
                            }
                            catch
                            {
                                id = 0;
                            }

                            // lấy subject
                            string sub = UtilityCtr.GetItemFirst(lsTopic[i], @"<a[\s]+class='title'[\s]+href='showthread.php.*?<\/a>");
                            sub = Regex.Replace(sub, @"<.*?>", "");

                            GetContent(link, sub, id, dtLastDate);
                            #endregion
                        }
                        else
                        {
                            if (pageIndex > 1) // nếu đây là trang thứ 2 trở đi
                            {
                                _pageLimit = pageIndex; // đánh dấu trang hiện hành này là trang giới hạn, vì các chủ để từ trang sau luôn có ngày reply nhỏ hơn ngày giới hạn
                                break;
                            }
                        }
                    }
                    catch
                    { }
                }
            }
            catch
            { }
        }

        /// <summary>
        /// Lấy nội dung theo link 1 topics
        /// </summary>
        /// <param name="forumTopicEntity"></param>
        public void GetContent(string lnk, string sub, long idTopic, DateTime lastModify)
        {
            try
            {
                // ghi log để test
                TraceLog_Status(_source, _blockId, " --- " + lnk);

                string html = GetWebContent(lnk, 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip

                if (html.IsStringNullOrEmpty() == true)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                #region lấy tên danh mục
                var catLis = html.GetElements(@"<li[\s]+class='navbit'>.*?<\/li>", false, PatternType.Regex);
                string catName = "";
                if (catLis == null || catLis.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Lấy tên danh mục trên thanh navigation rỗng, có thể website nguồn có sự thay đổi souce code!");
                }
                else
                {
                    catName = Regex.Replace(catLis[catLis.Count - 1], @"<.*?>", "").Trim();
                }
                #endregion

                // xóa các trích dẫn nếu có
                html = Regex.Replace(html, @"(<div[\s]+class='bbcode_container'>)(.*?)((<\/div>){2,})", "");

                var lsDiv = UtilityCtr.GetListItem(html, @"<div[\s]+id='post_message_[\d]+'>.*?<\/blockquote><\/div>");

                if (lsDiv == null || lsDiv.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Bài viết và Bình luận = 0, có thể website nguồn có sự thay đổi souce code, hay ip bị block!");
                    return;
                }

                // lấy nội dung
                string content = Regex.Replace(lsDiv[0], @"(<h4.*?<\/h4>)|(<ul style='.*?' id='tin_lien_quan'>.*?<\/ul>)|(<.*?>)", " "); // xóa các cụm tin liên quan
                content = Regex.Replace(content, @"[\s]+", " ").Trim();//replace nhiều khoảng trắng thành 1 khoảng trắng

                #region [lấy bình luận trang đầu]
                List<string> lsCmt = new List<string>();
                for (int i = 1; i < lsDiv.Count; i++)
                {
                    string cmt = Regex.Replace(lsDiv[i], @"<.*?>", " ");
                    cmt = Regex.Replace(cmt, @"[\s]+", " ").Trim();//replace nhiều khoảng trắng thành 1 khoảng trắng

                    lsCmt.Add(cmt);
                }
                #endregion

                #region lấy bình luận từ trang 2 trở đi
                try
                {
                    string pager = html.GetElement(@"Trang[\s]+[\d]+[\s]+trong[\s]+[\d]+<\/a>", false, PatternType.Regex);
                    List<string> lsNumPage = UtilityCtr.GetListItem(pager, @"[\d]+");

                    int totalPage = Convert.ToInt32(lsNumPage[lsNumPage.Count - 1]);
                    for (int i = 2; i <= totalPage; i++) // duyêt từ trang số 2 trở đi
                    {
                        string htmlSub = GetWebContent(lnk + "/page" + i.ToString(), 250); // nghỉ 250 mili giây trước khi gửi request, để tránh bị block Ip;

                        // xóa các trích dẫn nếu có
                        htmlSub = Regex.Replace(htmlSub, @"(<div[\s]+class='bbcode_container'>)(.*?)((<\/div>){2,})", "");

                        /// lấy danh sách
                        var lsCmtSub = UtilityCtr.GetListItem(htmlSub, @"<div[\s]+id='post_message_[\d]+'>.*?<\/blockquote><\/div>");
                        for (int j = 0; j < lsCmtSub.Count; j++)
                        {
                            string cmtSub = Regex.Replace(lsCmtSub[j], @"<.*?>", "");
                            cmtSub = Regex.Replace(cmtSub, @"[\s]+", " ").Trim();//replace nhiều khoảng trắng thành 1 khoảng trắng

                            lsCmt.Add(cmtSub);
                        }
                    }
                }
                catch { }
                #endregion

                #region [Lưu lại]

                ContentEntity entity = new ContentEntity();

                entity.Category = catName;
                entity.Comments = lsCmt;
                entity.Content = content;
                entity.Id = idTopic;
                entity.LastModify = lastModify;
                entity.Link = lnk;
                entity.Source = _source;
                entity.Summury = "";
                entity.Title = sub;

                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- Comments: " + lsCmt.Count.ToString() + " -- Last modify: " + lastModify.ToString("yyyy-MM-dd hh:mm:ss tt"));
                // lưu vào file json
                string file = LogFileJson(entity);
                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- File json: " + file);

                // tăng số topic lên 1 để thực hiện việc thống kê
                _totalTopic = _totalTopic + 1;
                UtilityCtr.TraceSettingTime(_source, _timeStart, _totalTopic, _dtLimit.ToString("yyyy-MM-dd hh:mm:ss tt"));
                #endregion
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- --- Error: " + ex.Message); // ghi log để test
            }
        }
    }
}
